# -*- coding: utf-8 -*-
"""
Base for all repositories.
"""
import os.path
import pickle
from processors.changeinfo import ChangeInfo
from myutil import myutil
import logging

class SingleRepositoryProcessor: #pylint: disable-msg=R0902,R0921
    """
    Processes single repository or group of repositories.
    """
    _changes_file_postfix = "_changes.pckl"
    
    def __init__(self, settings, storepath, oldpath, conf):
        """
        Creates the processor.
        
        settings: configuration settings
        title: name of the repository
        location: location of the repository
        storepath: path where processed ids are stored
        oldpath: path where old ids are stored
        pullurl: in case pull is required
        webrl: where web frontend is located for the repository
        flavor: flavor - web frontend flavor for the repositories (depend on repository type)
        login: user name for the repository
        password: password for the repository
        """
        self.settings = settings
        self.title = conf['title'] if 'title' in conf else ""
        self.location = conf['location']
        self.storepath = storepath
        self.oldpath = oldpath
        self.old_ids = set()
        self.emails = set()
        self.changes = []
        # remote url might be None
        self.pullurl = conf['pullurl'] if 'pullurl' in conf else None
        self.weburl = conf['weburl'] if 'weburl' in conf else None
        if self.weburl is not None and not self.weburl.endswith("/"):
            self.weburl = self.weburl + "/"
        self.flavor = conf['flavor'] if 'flavor' in conf else None
        self.login = conf['login'] if 'login' in conf else None
        self.password = conf['password'] if 'password' in conf else None
        
    def initialize(self):
        """
        Initialize the repository.
        """
        pass
                
    def process(self):
        """
        Processes everything.
        """
        self._load_ids()
        self._gather_log_info()
        self._remove_duplicates()
        self._filter_ids()

    def get_store_filename(self):
        """
        Return name for new id storage. 
        """
        file_name = os.path.join(self.storepath, \
                        myutil.get_repo_file_name(self.location) + \
                        self._changes_file_postfix)
        return file_name

    def _get_old_store_filename(self):
        """
        Return name for old id storage.
        """
        file_name = os.path.join(self.oldpath, \
                     myutil.get_repo_file_name(self.location) + \
                     self._changes_file_postfix)
        return file_name

    def save_ids(self):
        """
        Saves all ids which were processed.
        """
        file_name = self.get_store_filename()
        if os.path.exists(file_name):
            os.rename(file_name, self._get_old_store_filename())
        output = open(file_name, "w")
        ids = set([x.change_id for x in self.changes])
        ids.update(self.old_ids)
        try:
            pickle.dump(ids, output, 0)  # Text mode
        finally:
            output.close()

    def _load_ids(self):
        """
        Load ids from previous storage.
        """
        file_name = self.get_store_filename()
        logging.info("-> Reading ids from " + file_name)
        try:
            output = open(file_name, "r")
            try:
                ids = pickle.load(output)
                self.old_ids = ids
            finally:
                output.close()
        except IOError:
            self.old_ids = []
    
    def _remove_duplicates(self):
        """
        Remove duplicate ids.
        """
        self.changes = list(set(self.changes))

    def _filter_ids(self):
        """
        Remove ids which were already processed before.
        """
        self.changes = [x for x in self.changes \
                            if x.change_id not in self.old_ids]
        self.changes.sort(key=ChangeInfo.get_date)

    def _gather_log_info(self):
        '''
        Gathers information about changes in local repository and
        adds them to the dictionary.s
        '''
        raise NotImplementedError()

    def _append_change_info(self, change_info):
        """
        Appends change information to list of changes and does some
        email magic.
        """
        self.changes.append(change_info)
        if change_info.email is not None:
            self.emails.add(change_info.email)

    def __str__(self):
        return str(self.changes)
    
    def __repr__(self):
        return "<%s >:%s" % (self.__class__, str(self))
